#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import re

def reverse_str(string:str):
    tmp = [c for c in string]
    tmp.reverse()
    return ''.join(tmp)

def indent_str(indent, /, s:str=''):
    indent_s = ' ' * 4 * indent
    count = s.count('\n') - 1
    return indent_s + s.replace('\n', '\n' + indent_s, count)

def replace_blank(string):
    return re.sub(r"\s+", r" ", string.strip())

def extract_str(string, l, r):
    tmp = string
    pos = tmp.find(l)
    if pos >= 0:
        tmp = tmp[pos+1:]
    pos = tmp.rfind(r)
    tmp = tmp[:pos]
    return tmp.strip()

def extract_side_str(string, l, r):
    sl, sr = '', ''
    pos = string.find(l)
    if pos >= 0:
        sl = string[:pos]

    pos = string.rfind(r)
    if pos >= 0:
        sr = string[pos+1:]
    return sl.strip(), sr.strip()

def preprocess_text(text):
    lines = text.splitlines()
    # reverse
    for i in range(len(lines) - 1, -1, -1):
        if lines[i].startswith('#'):
            lines.pop(i)
    return '\n'.join(lines)

def text2tokens(text):
    splits = [';', '{', '}']
    tmp = preprocess_text(text)
    for ch in splits:
        tmp = tmp.replace(ch, ' {} '.format(ch))
    tmp = replace_blank(tmp)
    tokens = re.split('\s', tmp)
    return tokens

def text2lines(text):
    retlines = []
    nr_brace_l, nr_brace_r = 0, 0
    tmp_line = ''

    tokens = text2tokens(text)
    for i, line in enumerate(tokens):
        tmp_line += ' ' + line
        if line == '{':
            nr_brace_l += 1
        elif line == '}':
            nr_brace_r += 1
        elif line == ';':
            if nr_brace_l == nr_brace_r:
                nr_brace_l, nr_brace_r = 0, 0
                retlines.append(tmp_line.strip())
                tmp_line = ''

    # int main() {}
    if nr_brace_l == nr_brace_r:
        retlines.append(tmp_line.strip())
    else:
        pass
        # log.warning('{}'.format(tmp_line))
    return retlines

def _____find_end(buf, pos, ch_end=";"):
    buf = buf[pos+1:]
    end = pos + buf.find(ch_end)
    cnt_l, cnt_r = buf[:end].count('{'), buf[:end].count('}')
    if cnt_l == cnt_r:
        if end < pos:
            return -1, 0
        return len(buf) - 1, cnt_l

    while cnt_l != cnt_r:
        end += buf[end+1:].find(ch_end)
        if end < pos:
            break
        cnt_l, cnt_r = buf[:end].count('{'), buf[:end].count('}')

    if cnt_l == cnt_r:
        if end < pos:
            return -1, 0
        return end, cnt_l
    return -1, 0

def find_end(buf, pos, ch_end=";"):
    cnt_l, cnt_r = 0, 0
    end = -1
    for i, ch in enumerate(buf):
        if i < pos:
            continue
        if ch == "{":
            cnt_l += 1
        elif ch == "}":
            cnt_r += 1
            if cnt_r > cnt_l:  # error
                break
        end = i
        if ch == ch_end:
            if cnt_l == cnt_r:
                break

    # maybe no ch_end
    if cnt_l == cnt_r:
        if cnt_l == 0 and not buf[pos:end].strip():
            return -1, 0
        return end, cnt_r
    return -1, 0
